package com.wzk.travelspringboot.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzk.travelspringboot.common.LogToFile;
import com.wzk.travelspringboot.common.RedisConstant;
import com.wzk.travelspringboot.dao.UserDAO;
import com.wzk.travelspringboot.dto.ChangePasswordDTO;
import com.wzk.travelspringboot.dto.LoginDTO;
import com.wzk.travelspringboot.dto.RegisterDTO;
import com.wzk.travelspringboot.dto.Result;
import com.wzk.travelspringboot.entity.User;
import com.wzk.travelspringboot.enumerate.RoleEnum;
import com.wzk.travelspringboot.enumerate.SexEnum;
import com.wzk.travelspringboot.enumerate.StateEnum;
import com.wzk.travelspringboot.service.UserService;
import com.wzk.travelspringboot.utils.MinioUtil;
import com.wzk.travelspringboot.utils.PasswordUtil;
import com.wzk.travelspringboot.vo.UserVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * @Author: WangZiKang
 * @Date: 2025/1/4 22:09
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserDAO, User> implements UserService {

    private final StringRedisTemplate stringRedisTemplate;

    private final UserDAO userDAO;

    private final MinioUtil minioUtil;

    @Value("${password.key}")
    private String key;

    public static final Logger logger = Logger.getLogger(UserServiceImpl.class.getName());

    @Override
    public Result login(LoginDTO dto) {
        //1.校验验证码是否过期
        String code = stringRedisTemplate.opsForValue().get(RedisConstant.CAPTCHA_CODE_KEY + dto.getCode());
        if (StrUtil.isBlank(code)){
            return Result.failed("验证码已过期！");
        }
        if (!code.equals(dto.getCode())){
            return Result.failed("验证码不正确！");
        }
        //2.判断用户是否存在
        User user = userDAO.queryUserByNickName(dto.getUsername());
        if (user == null){
            return Result.failed("用户名或密码错误！");
        }
        if (user.getState() != 1){
            return Result.failed("用户状态异常！请联系管理员");
        }
        //3.校验用户密码
        String password = user.getPassword();
        String decrypt = PasswordUtil.decrypt(password,key);
        if (StrUtil.isNotBlank(decrypt) && decrypt.equals(dto.getPassword())){
            //缓存到redis同一时刻只能一人登录并且设置过期时间 1小时
            //stringRedisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY+user.getNikeName(),"",RedisConstant.USER_LOGIN_TIME, TimeUnit.MINUTES);
            UserVO userVO = new UserVO();
            userVO.setId(user.getId());
            userVO.setNickName(user.getNickName());
            userVO.setPhone(user.getPhone());
            userVO.setEmail(user.getEmail());
            userVO.setAge(user.getAge());
            userVO.setAvatar(user.getAvatar());
            userVO.setRole(RoleEnum.fromCode(user.getRole()));
            userVO.setSex(SexEnum.fromCode(user.getSex()));
            userVO.setState(StateEnum.fromCode(user.getState()));
            return Result.success("登陆成功！",userVO);
        }else {
            return Result.failed("用户名或密码错误！");
        }
    }

    @Override
    public Result register(RegisterDTO dto) {
        //0.判断密码和确认密码是否相同
        if (!dto.getPassword().equals(dto.getRePassword())){
            return Result.failed("两次输入的密码不一致！");
        }
        //1.判断昵称是否已经被占用
        User user = userDAO.queryUserByNickName(dto.getNikeName());
        if (user != null){
            return Result.failed("此昵称已经被占用");
        }
        //2.判断手机号是否已经被使用
        int i = userDAO.queryUserCountByPhone(dto.getPhone());
        if (i > 0){
            return Result.failed("此手机号已经注册过了");
        }
        //3.判断邮箱是否存在
        int i1 = userDAO.queryUserCountByEmail(dto.getEmail());
        if (i1 > 0){
            return Result.failed("邮箱已经被使用了");
        }
        //4.判断邮箱验证码是否过期
        String code = stringRedisTemplate.opsForValue().get(RedisConstant.EMAIL_CODE_KEY + dto.getEmail());
        if (StrUtil.isBlank(code)){
            return Result.failed("验证码已经失效！请重新获取");
        }
        if (!code.equals(dto.getEmailCode())){
            return Result.failed("验证码不正确");
        }
        //5.保存用户
        User u = new User();
        u.setAge(dto.getAge());
        if (dto.getSex() != null){
            u.setSex(dto.getSex());
        }
        u.setEmail(dto.getEmail());
        u.setPhone(dto.getPhone());
        u.setNickName(dto.getNikeName());
        u.setCreateTime(LocalDateTime.now());
        u.setUpdateTime(LocalDateTime.now());
        u.setPassword(PasswordUtil.encrypt(dto.getPassword(),key));
        boolean b = save(u);
        if (!b){
            return Result.failed("用户注册失败！出现未知错误请联系管理员");
        }
        //清除验证码缓存 减少内存占用
        stringRedisTemplate.delete(RedisConstant.EMAIL_CODE_KEY+dto.getEmail());
        return Result.success("用户注册成功！",null);
    }

    @Override
    public Result changeAvatar(Long aLong, MultipartFile avatar) {
        //1.判断文件类型是否合法
        boolean b = minioUtil.checkFileSuffix(avatar.getOriginalFilename());
        if (!b){
            return Result.failed("文件类型不合法");
        }
        //2.上传头像返回结果
        try {
            String url = minioUtil.uploadImageFile("user-avatar", avatar.getOriginalFilename(), avatar.getInputStream());
            //3.修改数据库用户头像url
            int i = userDAO.changeUserAvatarById(aLong, url);
            if (i <= 0){
                return Result.failed("上传头像失败！出现未知错误请类型管理");
            }
            return Result.success("修改头像成功！",url);
        }catch (Exception e){
            LogToFile.logToFile("用户上传头像出现异常，信息:"+e,logger,"user_upload_avatar_err");
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result changePwd(ChangePasswordDTO dto) {
        //1.查询用户判断是否存在
        User user = userDAO.selectById(dto.getUserId());
        if (user == null || user.getState() != 1){
            return Result.failed("用户不存在或状态异常");
        }
        //2.校验原始密码是否正确
        String originalPassword = PasswordUtil.decrypt(user.getPassword(), key);
        if (!originalPassword.equals(dto.getOldPassword())){
            return Result.failed("原始密码不正确");
        }
        //3.校验新密码和确认密码是否正确
        if (!dto.getNewPassword().equals(dto.getConfirmPassword())){
            return Result.failed("请保证确认密码和新密码一致");
        }
        //4.修改密码
        int i = userDAO.changeUserPwdById(dto.getUserId(), PasswordUtil.encrypt(dto.getNewPassword(),key));
        if (i <= 0){
            return Result.failed("修改失败！出现未知错误请联系管理员");
        }
        return Result.success("修改成功！");
    }

    @Override
    public Result adminLogin(LoginDTO dto) {
        //1.校验验证码是否过期
        String code = stringRedisTemplate.opsForValue().get(RedisConstant.CAPTCHA_CODE_KEY + dto.getCode());
        if (StrUtil.isBlank(code)){
            return Result.failed("验证码已过期！");
        }
        if (!code.equals(dto.getCode())){
            return Result.failed("验证码不正确！");
        }
        //2.判断用户是否存在
        User user = userDAO.queryUserByNickName(dto.getUsername());
        if (user == null){
            return Result.failed("用户名或密码错误！");
        }
        if (user.getState() != 1){
            return Result.failed("用户状态异常！请联系管理员");
        }
        //3.判断是否为管理员
        if (user.getRole() != 1){
            return Result.failed("抱歉您没有访问权限");
        }
        //3.校验用户密码
        String password = user.getPassword();
        String decrypt = PasswordUtil.decrypt(password,key);
        if (StrUtil.isNotBlank(decrypt) && decrypt.equals(dto.getPassword())){
            //缓存到redis同一时刻只能一人登录并且设置过期时间 1小时
            //stringRedisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY+user.getNikeName(),"",RedisConstant.USER_LOGIN_TIME, TimeUnit.MINUTES);
            UserVO userVO = new UserVO();
            userVO.setId(user.getId());
            userVO.setNickName(user.getNickName());
            userVO.setPhone(user.getPhone());
            userVO.setEmail(user.getEmail());
            userVO.setAge(user.getAge());
            userVO.setAvatar(user.getAvatar());
            userVO.setRole(RoleEnum.fromCode(user.getRole()));
            userVO.setSex(SexEnum.fromCode(user.getSex()));
            userVO.setState(StateEnum.fromCode(user.getState()));
            return Result.success("登陆成功！",userVO);
        }else {
            return Result.failed("用户名或密码错误！");
        }
    }

}
